%-----------------------------------------------------------------------------------
% This code has been adapted by Xin Zhang for purposes of course
% "AV423 Satellite Navigation" taught at School of Aeronautics & Astronautics, 
% Shanghai Jiao Tong University,
% from the SoftGNSS v3.0 code base developed for the
% text: "A Software-Defined GPS and Galileo Receiver: A Single-Frequency Approach"
% by Borre, Akos, et.al.
%-----------------------------------------------------------------------------------
function acqResults = acquisition(longSignal, settings)
%Function performs cold start acquisition on the collected "data". It
%searches for GPS signals of all satellites, which are listed in field
%"acqSatelliteList" in the settings structure. Function saves code phase
%and frequency of the detected signals in the "acqResults" structure.
%
%acqResults = acquisition(longSignal, settings)
%
%   Inputs:
%       longSignal    - 11 ms of raw signal from the front-end 
%       settings      - Receiver settings. Provides information about
%                       sampling and intermediate frequencies and other
%                       parameters including the list of the satellites to
%                       be acquired.
%   Outputs:
%       acqResults    - Function saves code phases and frequencies of the 
%                       detected signals in the "acqResults" structure. The
%                       field "carrFreq" is set to 0 if the signal is not
%                       detected for the given PRN number. 
 
%--------------------------------------------------------------------------
%                           SoftGNSS v3.0
% 
% Copyright (C) Darius Plausinaitis and Dennis M. Akos
% Written by Darius Plausinaitis and Dennis M. Akos
% Based on Peter Rinder and Nicolaj Bertelsen
%--------------------------------------------------------------------------
%This program is free software; you can redistribute it and/or
%modify it under the terms of the GNU General Public License
%as published by the Free Software Foundation; either version 2
%of the License, or (at your option) any later version.
%
%This program is distributed in the hope that it will be useful,
%but WITHOUT ANY WARRANTY; without even the implied warranty of
%MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
%GNU General Public License for more details.
%
%You should have received a copy of the GNU General Public License
%along with this program; if not, write to the Free Software
%Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301,
%USA.
%--------------------------------------------------------------------------

%CVS record:
%$Id: acquisition.m,v 1.1.2.12 2006/08/14 12:08:03 dpl Exp $

%% Initialization =========================================================

% Find number of samples per spreading code
samplesPerCode = round(settings.samplingFreq / ...
                        (settings.codeFreqBasis / settings.codeLength));

% Create two 1msec vectors of data to correlate with and one with zero DC
signal1 = longSignal(1 : samplesPerCode);
signal2 = longSignal(samplesPerCode+1 : 2*samplesPerCode);

signal0DC = longSignal - mean(longSignal);   %%Problems here....

% Find sampling period
ts = 1 / settings.samplingFreq;

% Find phase points of the local carrier wave 
phasePoints = (0 : (samplesPerCode-1)) * 2 * pi * ts;

% Number of the frequency bins for the given acquisition band (500Hz steps)

numberOfFrqBins = round(settings.acqSearchBand * 2 / settings.acqStep) + 1;
% Generate all B1I codes and sample them according to the sampling freq.
B1CodesTable = makeCodeTable(settings);


%--- Initialize arrays to speed up the code -------------------------------
% Search results of all frequency bins and code shifts (for one satellite)
results     = zeros(numberOfFrqBins, samplesPerCode);

% Carrier frequencies of the frequency bins
frqBins     = zeros(1, numberOfFrqBins);


%--- Initialize acqResults ------------------------------------------------
% Carrier frequencies of detected signals
acqResults.carrFreq     = zeros(1, 32);
% B1I code phases of detected signals
acqResults.codePhase    = zeros(1, 32);
% Correlation peak ratios of the detected signals
acqResults.peakMetric   = zeros(1, 32);

fprintf('(');

% Perform search for all listed PRN numbers ...
for PRN = settings.acqSatelliteList

%% Correlate signals ======================================================   
    %--- Perform DFT of B1I code ------------------------------------------
    caCodeFreqDom = conj(fft(B1CodesTable(PRN, :)));

    %--- Make the correlation for whole frequency band (for all freq. bins)
    for frqBinIndex = 1:numberOfFrqBins

        %--- Generate carrier wave frequency grid (0.5kHz step) -----------

        frqBins(frqBinIndex) = settings.IF - settings.acqSearchBand + ...
                               settings.acqStep * (frqBinIndex - 1);
        %--- Generate local sine and cosine -------------------------------
        sigCarr = exp(i*frqBins(frqBinIndex) * phasePoints);
        
        %--- "Remove carrier" from the signal -----------------------------
        I1      = real(sigCarr .* signal1);
        Q1      = imag(sigCarr .* signal1);
        I2      = real(sigCarr .* signal2);
        Q2      = imag(sigCarr .* signal2);

        %--- Convert the baseband signal to frequency domain --------------
        IQfreqDom1 = fft(I1 + j*Q1);
        IQfreqDom2 = fft(I2 + j*Q2);

        %--- Multiplication in the frequency domain (correlation in time
        %domain)
        convCodeIQ1 = IQfreqDom1 .* caCodeFreqDom;
        convCodeIQ2 = IQfreqDom2 .* caCodeFreqDom;

        %--- Perform inverse DFT and store correlation results ------------
        acqRes1 = abs(ifft(convCodeIQ1)) .^ 2;
        acqRes2 = abs(ifft(convCodeIQ2)) .^ 2;
        
        %--- Check which msec had the greater power and save that, will
        %"blend" 1st and 2nd msec but will correct data bit issues
        if (max(acqRes1) > max(acqRes2))
            results(frqBinIndex, :) = acqRes1;
        else
            results(frqBinIndex, :) = acqRes2;
        end
        
    end % frqBinIndex = 1:numberOfFrqBins

%% Look for correlation peaks in the results ==============================
    % Find the highest peak and compare it to the second highest peak
    % The second peak is chosen not closer than 1 chip to the highest peak
    
    %--- Find the correlation peak and the carrier frequency --------------
    [peakSize frequencyBinIndex] = max(max(results, [], 2));

    %--- Find code phase of the same correlation peak ---------------------
    [peakSize codePhase] = max(max(results));

    %--- Find 1 chip wide B1I code phase exclude range around the peak ----
    samplesPerCodeChip   = round(settings.samplingFreq / settings.codeFreqBasis);
    excludeRangeIndex1 = codePhase - samplesPerCodeChip;
    excludeRangeIndex2 = codePhase + samplesPerCodeChip;

    %--- Correct B1I code phase exclude range if the range includes array
    %boundaries
    if excludeRangeIndex1 < 2
        codePhaseRange = excludeRangeIndex2 : ...
                         (samplesPerCode + excludeRangeIndex1);
                         
    elseif excludeRangeIndex2 >= samplesPerCode
        codePhaseRange = (excludeRangeIndex2 - samplesPerCode) : ...
                         excludeRangeIndex1;
    else
        codePhaseRange = [1:excludeRangeIndex1, ...
                          excludeRangeIndex2 : samplesPerCode];
    end

    %--- Find the second highest correlation peak in the same freq. bin ---
    secondPeakSize = max(results(frequencyBinIndex, codePhaseRange));

    %--- Store result -----------------------------------------------------
    acqResults.peakMetric(PRN) = peakSize/secondPeakSize;
    %% 捕获结果
    % X = 1:size(results,2);
    % Y = 1:size(results,1);
    % Y = settings.IF - settings.acqSearchBand + ...
    %                            settings.acqStep * (Y - 1);
    % figure()
    % mesh(X,Y,results()/peakSize);
    % axis tight;
    % xlabel("测距码相位/chips");
    % ylabel("载波频率/MHz");
    % zlabel("归一化相关结果");
    % title(sprintf("PRN%d捕获结果",PRN));

    
    % If the result is above threshold, then there is a signal ...
    if (peakSize/secondPeakSize) > settings.acqThreshold

%% Fine resolution frequency search =======================================
        
        %--- Indicate PRN number of the detected signal -------------------
        fprintf('%02d ', PRN);


        NumOfFineBins = round(settings.acqStep / settings.acqFineStep) + 1;
        
        % Carrier frequencies of the frequency bins
        FineFrqBins     = zeros(1, NumOfFineBins);
        
        % Search results of all frequency bins
        FineResult = zeros(1,NumOfFineBins);
        
        %--- Generate B1I data and pilot codes sequence -------------------
        % settings.fineNoncoh ms long 
        load('B1I_Codes_PRN_1_63.mat');
        B1Code = CodeMat(PRN,:);
        B1Code(B1Code == 0) = -1;
        
        % Sampling index
        codeValueIndex = floor((ts * (1:settings.fineNoncoh*samplesPerCode)) / ...
                               (1/settings.codeFreqBasis));
        
        % Sampled data and pilot codes
        longB1Code = B1Code((rem(codeValueIndex, settings.codeLength) + 1));  
        
        %--- Find phase points of the local carrier wave -------------------
        finePhasePoints = (0 : (settings.fineNoncoh*samplesPerCode-1)) * 2 * pi * ts;
        
        % 10cm incoming signal
        sigFineACQ = longSignal(codePhase:codePhase + settings.fineNoncoh*samplesPerCode -1);
        
        % Coherent integration for each code
        sumPerCode1 = zeros(1,settings.fineNoncoh);

                
        %--- Search different frequency bins -------------------------------
        for FineBinIndex = 1 : NumOfFineBins
            
            % Carrier frequencies of the frequency bins
            FineFrqBins(FineBinIndex) = frqBins(frequencyBinIndex) -...
                             settings.acqStep/2 + settings.acqFineStep * (FineBinIndex - 1);
            % Generate local sine and cosine
            sigCarr20cm = exp(1i*FineFrqBins(FineBinIndex) * finePhasePoints);
            
            % Wipe off B1I code and carrier from incoming signals to 
            % produce baseband signal. This is for data channel
            basebandSig1 = longB1Code .* sigCarr20cm .* sigFineACQ;
            
            
            % Non-coherent integration for each code
            for index = 1:settings.fineNoncoh
                sumPerCode1(index) = sum( basebandSig1( samplesPerCode * ...
                                     (index-1)+1:samplesPerCode*index ) );                 
            end
            
            FineResult(FineBinIndex) = sum(abs(sumPerCode1));

        end % FineBinIndex = 1 : NumOfFineBins

        % Find the fine carrier freq. -------------------------------------
        % Corresponding to the largest noncoherent power
        [~,maxFinBin] = max(FineResult);
        acqResults.carrFreq(PRN) = FineFrqBins(maxFinBin);
        
        % Code phase acquisition result
        acqResults.codePhase(PRN) = codePhase;
        
        %signal found, if IF = 0 just change to 1 Hz to allow processing
        if(acqResults.carrFreq(PRN) == 0)
            acqResults.carrFreq(PRN) = 1;
        end
    else
        %--- No signal with this PRN --------------------------------------
        fprintf('. ');
    end   % if (peakSize/secondPeakSize) > settings.acqThreshold
    
end    % for PRN = satelliteList

%=== Acquisition is over ==================================================
fprintf(')\n');
